package mail.fetch.netease;

import mail.entity.ProxyEntity;
import mail.exception.ContentMissedException;
import mail.exception.InitException;
import mail.exception.MailTypeException;
import mail.util.HttpResponseUtil;
import mail.util.JsInvoker;
import mail.util.RegexSearcher;

import java.io.IOException;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Objects;

/**
 * @author: Hanjiafeng
 * @date: Created in 17:15 2019/2/28
 * @desc:
 */
class Login11 {

    /**
     * 定义请求发送对象
     */
    private HttpClient httpClient;

    /**
     * 定义请求Builder
     */
    private HttpRequest.Builder baseRequestBuilder;

    /**
     * 定义cookie管理器
     */
    private CookieManager cookieManager;

    /**
     * 用户名
     */
    private String account;

    /**
     * 密码
     */
    private String password;

    /**
     * 当前邮箱类型
     */
    private MailType mailType;

    private String pkid;

    private String rtid;

    private String utid;

    private JsInvoker jsInvoker;

    Login11(ProxyEntity proxyEntity) {

        //初始化CookieManager并设置接受所有cookie
        cookieManager = new CookieManager();
        cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);

        HttpClient.Builder clientBuilder = HttpClient.newBuilder()
                .connectTimeout(Duration.ofMinutes(1))
                .cookieHandler(cookieManager)
                //禁止自动跳转
                .followRedirects(HttpClient.Redirect.NEVER);
        //如果代理不为null,设置代理
        if (!Objects.isNull(proxyEntity)) {
            clientBuilder.proxy(ProxySelector.of(new InetSocketAddress(proxyEntity.getIp(), proxyEntity.getPort())));
        }
        //设置通用参数
        httpClient = clientBuilder
                .build();
        //设置通用参数
        baseRequestBuilder = HttpRequest.newBuilder()
                .timeout(Duration.ofMinutes(1))
                .setHeader("Accept-Encoding", "gzip, deflate, br")
                .setHeader("Accept-Language", "zh-CN,zh;q=0.9")
                .setHeader("DNT", "1")
                .setHeader("Upgrade-Insecure-Requests", "1")
                .setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3664.3 Safari/537.36");

        //加密文件路径
        String filePath = "F:\\workspace\\java\\MailCrawler\\src\\main\\resources\\Encrypt163.js";
        jsInvoker = new JsInvoker(filePath);
        //生成两个随机id
        rtid = getRandomId();
        utid = getRandomId();
    }

    /**
     * 获取CookieManager
     *
     * @param mailType 邮箱类型
     * @param account  账号
     * @param password 密码
     * @return CookieManager
     * @throws MailTypeException      邮箱类型错误
     * @throws InitException          初始化错误
     * @throws ContentMissedException 没有获取到数据
     */
    CookieManager getCookieManager(MailType mailType, String account, String password) throws
            MailTypeException, InitException, ContentMissedException {
        if (MailType.isNotNetEase(mailType)) {
            throw new MailTypeException("邮箱类型错误,仅可是163,126,yeah邮箱");
        }
        this.mailType = mailType;
        this.account = account;
        this.password = password;

        //addCookie();

        getPkId();
        initCookie();
        String tk = getTk();
        commitProof(tk);
        ntesDoor();
        return cookieManager;
    }

    /**
     * 获取邮箱特征id
     *
     * @throws InitException 初始化失败
     */
    private void getPkId() throws InitException {
        //选择uri
        String uri163 = "https://mail.163.com/";
        String uri126 = "https://www.126.com/";
        String uriYeah = "https://www.yeah.net/";
        String uri = MailSwitcher.switchParameter(mailType, uri163, uri126, uriYeah);
        HttpRequest httpRequest = baseRequestBuilder
                .copy()
                .setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
                .uri(URI.create(uri))
                .build();
        try {
            HttpResponse<byte[]> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());
            String body = HttpResponseUtil.getBody(response);
            pkid = RegexSearcher.matchFirst(body, "(?<= pkid: ')((?!').)*(?=')");
            if (pkid.isEmpty() || pkid.isBlank()) {
                throw new InitException("网易邮箱初始化失败,未获取到pkid:" + body);
            }
        } catch (IOException | InterruptedException e) {
            throw new InitException("网易邮箱初始化失败,未获取到pkid");
        }
    }

    /**
     * 初始化cookie
     *
     * @throws InitException 初始化失败
     */
    private void initCookie() throws InitException {
        String uri163 = "https://dl.reg.163.com/dl/ini?pd=mail163&pkid=" + pkid + "&pkht=mail.163.com&topURL=https%3A%2F%2Fmail.163.com%2F&rtid=" + rtid + "&nocache=" + System.currentTimeMillis();
        String uri126 = "https://passport.126.com/dl/ini?pd=mail126&pkid=" + pkid + "&pkht=mail.126.com&topURL=https%3A%2F%2Fwww.126.com%2F&rtid=" + rtid + "&nocache=" + System.currentTimeMillis();
        String uriYeah = "https://passport.yeah.net/dl/ini?pd=mailyeah&pkid=" + pkid + "&pkht=mail.yeah.net&topURL=https%3A%2F%2Fwww.yeah.net%2F&rtid=" + rtid + "&nocache=" + System.currentTimeMillis();
        String uri = MailSwitcher.switchParameter(mailType, uri163, uri126, uriYeah);
        HttpRequest httpRequest = baseRequestBuilder
                .copy()
                .setHeader("Accept", "*/*")
                .setHeader("Content-Type", "application/json")
                .setHeader("Cookie", "starttime=; JSESSIONID-WYTXZDL=OqRstPvHZtY09HKLSTgUdwIgui0%2FHlLKFRyhljRy%5C6pBOU634khBM%2FxuV5bgN2ouhZX8i7DVTbvqE6FiLj09yzJZ2swqZ42tFTFkiYMJ3Z6GKqw2%2BtKiw%2BRjKi56BZSonOL9kjgn%2FaHbi3UqQyi2fvBsJ1fjAd4b%5CsNnLx%5CiGoIGDidz%3A1546412006104; _ihtxzdilxldP8_=30; utid=" + utid)
                .uri(URI.create(uri))
                .build();
        try {
            httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());
        } catch (IOException | InterruptedException e) {
            throw new InitException("网易邮箱初始化Cookie失败");
        }
    }

    /**
     * 获取tk
     *
     * @return tk
     * @throws InitException          初始化失败
     * @throws ContentMissedException 未获取到tk
     */
    private String getTk() throws InitException, ContentMissedException {
        String tk;

        String uri163 = "https://dl.reg.163.com/dl/gt?un=" + account + "&pkid=" + pkid + "&pd=mail163&topURL=https%3A%2F%2Fmail.163.com%2F&rtid=" + rtid + "&nocache=" + System.currentTimeMillis();
        String uri126 = "https://passport.126.com/dl/gt?un=" + account + "&pkid=" + pkid + "&pd=mail126&topURL=https%3A%2F%2Fwww.126.com%2F&rtid=" + rtid + "&nocache=" + System.currentTimeMillis();
        String uriYeah = "https://passport.yeah.net/dl/gt?un=" + account + "&pkid=" + pkid + "&pd=mailyeah&topURL=https%3A%2F%2Fwww.yeah.net%2F&rtid=" + rtid + "&nocache=" + System.currentTimeMillis();
        String uri = MailSwitcher.switchParameter(mailType, uri163, uri126, uriYeah);
        HttpRequest httpRequest = baseRequestBuilder
                .copy()
                .setHeader("Content-Type", "application/json")
                .setHeader("Accept", "*/*")
                .setHeader("Cookie", "starttime=; JSESSIONID-WYTXZDL=OqRstPvHZtY09HKLSTgUdwIgui0%2FHlLKFRyhljRy%5C6pBOU634khBM%2FxuV5bgN2ouhZX8i7DVTbvqE6FiLj09yzJZ2swqZ42tFTFkiYMJ3Z6GKqw2%2BtKiw%2BRjKi56BZSonOL9kjgn%2FaHbi3UqQyi2fvBsJ1fjAd4b%5CsNnLx%5CiGoIGDidz%3A1546412006104; _ihtxzdilxldP8_=30; utid=" + utid)
                .uri(URI.create(uri))
                .build();
        try {
            HttpResponse<byte[]> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());
            String body = HttpResponseUtil.getBody(response);
            tk = RegexSearcher.matchFirst(body, "(?<=\"tk\":\")((?!\").)*(?=\")");
            if (tk.isBlank() || tk.isEmpty()) {
                throw new ContentMissedException("未获取到TK:" + body);
            }
        } catch (IOException | InterruptedException e) {
            throw new InitException("网易邮箱获取tk失败");
        }

        return tk;
    }

    /**
     * 提交登录参数
     *
     * @param tk tk
     * @throws InitException 提交失败
     */
    private void commitProof(String tk) throws InitException {
        String uri163 = "https://dl.reg.163.com/dl/l";
        String uri126 = "https://passport.126.com/dl/l";
        String uriYeah = "https://passport.yeah.net/dl/l";
        String uri = MailSwitcher.switchParameter(mailType, uri163, uri126, uriYeah);
        String encryptPwd = encryptPassword(password);
        String data163 = "{\"un\":\"" + account + "\",\"pw\":\"" + encryptPwd + "\",\"pd\":\"mail163\",\"l\":0,\"d\":10,\"t\":" + System.currentTimeMillis() + ",\"pkid\":\"" + pkid + "\",\"domains\":\"\",\"tk\":\"" + tk + "\",\"pwdKeyUp\":1,\"topURL\":\"https://mail.163.com/\",\"rtid\":\"" + rtid + "\"}";
        String data126 = "{\"un\":\"" + account + "\",\"pw\":\"" + encryptPwd + "\",\"pd\":\"mail126\",\"l\":0,\"d\":10,\"t\":" + System.currentTimeMillis() + ",\"pkid\":\"" + pkid + "\",\"domains\":\"\",\"tk\":\"" + tk + "\",\"pwdKeyUp\":1,\"topURL\":\"https://www.126.com/\",\"rtid\":\"" + rtid + "\"}";
        String dataYeah = "{\"un\":\"" + account + "\",\"pw\":\"" + encryptPwd + "\",\"pd\":\"mailyeah\",\"l\":0,\"d\":10,\"t\":" + System.currentTimeMillis() + ",\"pkid\":\"" + pkid + "\",\"domains\":\"\",\"tk\":\"" + tk + "\",\"pwdKeyUp\":1,\"topURL\":\"https://www.yeah.net/\",\"rtid\":\"" + rtid + "\"}";
        String postData = MailSwitcher.switchParameter(mailType, data163, data126, dataYeah);
        HttpRequest httpRequest = baseRequestBuilder
                .copy()
                .setHeader("Content-Type", "application/json")
                .setHeader("Cookie", "starttime=; JSESSIONID-WYTXZDL=OqRstPvHZtY09HKLSTgUdwIgui0%2FHlLKFRyhljRy%5C6pBOU634khBM%2FxuV5bgN2ouhZX8i7DVTbvqE6FiLj09yzJZ2swqZ42tFTFkiYMJ3Z6GKqw2%2BtKiw%2BRjKi56BZSonOL9kjgn%2FaHbi3UqQyi2fvBsJ1fjAd4b%5CsNnLx%5CiGoIGDidz%3A1546412006104; _ihtxzdilxldP8_=30; utid=" + utid)
                .setHeader("Accept", "*/*")
                .uri(URI.create(uri))
                .method("POST", HttpRequest.BodyPublishers.ofString(postData))
                .build();
        try {
            httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());
        } catch (IOException | InterruptedException e) {
            throw new InitException("网易邮箱提交登录参数失败");
        }
    }

    /**
     * 获取cookie
     *
     * @throws InitException 提交失败
     */
    private void ntesDoor() throws InitException {
        String uri163 = "https://mail.163.com/entry/cgi/ntesdoor?";
        String uri126 = "https://mail.126.com/entry/cgi/ntesdoor?";
        String uriYeah = "https://mail.yeah.net/entry/cgi/ntesdoor?";
        String uri = MailSwitcher.switchParameter(mailType, uri163, uri126, uriYeah);
        String data163 = "style=-1&df=mail163_letter&allssl=true&net=&language=-1&from=web&race=&iframe=1&url2=https%3A%2F%2Fmail.163.com%2Ferrorpage%2Ferror163.htm&product=mail163";
        String data126 = "style=-1&df=mail126_letter&allssl=true&net=&language=-1&from=web&race=&iframe=1&url2=https://mail.126.com/errorpage/error126.htm&product=mail126";
        String dataYeah = "style=-1&df=webmailyeah&allssl=true&net=&language=-1&from=web&race=&iframe=1&url2=https://mail.yeah.net/errorpage/err_yeah.htm&product=webmailyeah";
        String postData = MailSwitcher.switchParameter(mailType, data163, data126, dataYeah);
        HttpRequest httpRequest = baseRequestBuilder
                .copy()
                .setHeader("Content-Type", "application/x-www-form-urlencoded")
                .setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
                .uri(URI.create(uri))
                .method("POST", HttpRequest.BodyPublishers.ofString(postData))
                .build();
        try {
            httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());
        } catch (IOException | InterruptedException e) {
            throw new InitException("网易邮箱重定向错误");
        }
    }

    /**
     * 获取rtid/utid
     *
     * @return rtid/utid
     */
    private String getRandomId() {

        String method = "getId()";

        return jsInvoker.invokeJs(method);
    }

    /**
     * 加密密码
     *
     * @param rawPwd 原始密码
     * @return 加密后的密码
     */
    private String encryptPassword(String rawPwd) {

        String method = "MP.encrypt2('" + rawPwd + "')";

        return jsInvoker.invokeJs(method);
    }
}
